package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.lkd.common.VMSystem;
import com.lkd.config.ConsulConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.dao.OrderDao;
import com.lkd.feign.UserService;
import com.lkd.vo.*;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.VMService;
import com.lkd.service.OrderService;
import com.lkd.utils.DistributedLock;
import com.lkd.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo,orderNo);
        return this.getOne(qw);
    }


    @Autowired
    private  VMService  vmService;
    @Autowired
    private UserService userService;
    @Autowired
    private  MqttProducer  mqttProducer;

    /***
     * 根据订单号查询订单
     */
    public  OrderEntity   findOrderEntityById(String  orderNo){
       return    this.getByOrderNo(orderNo);
    }


    //出货
    //出货主题为vm/售货机编号/vendout
    @Override
    public boolean vendOut(String orderNo) {
        //1-根据订单编号查询订单
        OrderEntity orderEntity = findOrderEntityById(orderNo);
        if(orderEntity==null){
            throw  new LogicException("该订单不存在");
        }
        //2-修改订单支付状态为已支付
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_PAYED);
        //3-更改支付状态为已支付
        orderEntity.setStatus(VMSystem.ORDER_STATUS_PAYED);
        this.updateById(orderEntity);
        //4-用emq发送异步请求售货机微服务出货
        VendoutContract vdc = new VendoutContract();
        VendoutData vdd = new VendoutData();
        vdd.setOrderNo(orderNo);
        vdd.setSkuId(orderEntity.getSkuId());
        vdc.setInnerCode(orderEntity.getInnerCode());
        vdc.setVendoutData(vdd);
        try {
           mqttProducer.send(TopicConfig.getVendoutTopic(orderEntity.getInnerCode()),2,vdc);
           return true;
        } catch (JsonProcessingException e) {
            log.info("向售货机微服务发送消息失败");
            e.printStackTrace();
            return false;
        }
    }

    @Autowired
    private  ConsulConfig consulConfig;
    @Autowired
private  RedisTemplate<String,String> redisTemplate;
    //创建订单
    @Override
    public OrderEntity createOrder(PayVO payVO) {
        OrderEntity orderEntity = new OrderEntity();
        //设置openId
        orderEntity.setOpenId(payVO.getOpenId());
        //设置支付状态
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_NOPAY);//待支付状态
        if(payVO.getInnerCode()==null||payVO.getSkuId()==null){
            throw new LogicException("订单参数错误");
        }
        //判断是否有库存,feign远程调用vmService.hasCapacity
        Boolean flag = vmService.hasCapacity(payVO.getInnerCode(), Long.valueOf(payVO.getSkuId()));
        //获取售货机相关信息
        if (flag) {

            //分布式锁，机器同一时间只能处理一次出货
            DistributedLock lock = new DistributedLock(consulConfig.getConsulRegisterHost(), consulConfig.getConsulRegisterPort());
            DistributedLock.LockContext lockContext = lock.getLock(payVO.getInnerCode(), 60);

            if(!lockContext.isGetLock()){
                throw new LogicException("机器出货中请稍后再试");
            }
            //存入redis中是为了释放锁
            redisTemplate.boundValueOps(VMSystem.VM_LOCK_KEY_PREF+payVO.getInnerCode()).set(lockContext.getSession(),Duration.ofSeconds(60));



            orderEntity.setOrderNo(payVO.getInnerCode()+System.nanoTime());
            VmVO vmInfo = vmService.getVMInfo(payVO.getInnerCode());
            BeanUtils.copyProperties(vmInfo,orderEntity);
            orderEntity.setAddr(vmInfo.getNodeAddr());
            //获取商品相关信息
            SkuVO sku = vmService.getSku(payVO.getSkuId());
            BeanUtils.copyProperties(sku,orderEntity);
            orderEntity.setAmount(sku.getPrice());//金额
            orderEntity.setStatus(VMSystem.ORDER_STATUS_CREATE);
            //设置合作商分账金额
            PartnerVO partner = userService.getPartner(vmInfo.getOwnerId());
            BigDecimal bg = new BigDecimal(sku.getPrice());
            int bill = bg.multiply(new BigDecimal(partner.getRatio())).divide(new BigDecimal(100), 0, RoundingMode.HALF_UP).intValue();
            orderEntity.setBill(bill);
            //保存实体类，返回参数为订单实体类
            this.save(orderEntity);
            //向emq发送延时任务（时间为600s）
            mqttProducer.send("$delayed/600"+TopicConfig.ORDER_CHECK_TOPIC,2,orderEntity.getOrderNo());
            return  orderEntity;
        }else{
            throw new LogicException("该商品已售空");
        }

    }

}
